﻿using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.MySQL;
using Volo.Abp.EventBus;
using Volo.Abp.EventBus.Abstractions;
using Volo.Abp.Modularity;
using Volo.Abp.Uow;
using WorkFlowCore.Authorization;
using WorkFlowCore.Common.SimplePluginLoaders;
using WorkFlowCore.Conditions;
using WorkFlowCore.Framework.Authorization;
using WorkFlowCore.Framework.Conditions;
using WorkFlowCore.Framework.EventHandlers;
using WorkFlowCore.Framework.Repositories4EF;
using WorkFlowCore.Framework.UserSelectors;
using WorkFlowCore.IRepositories;
using WorkFlowCore.UserSelectors;
using Microsoft.Data.Sqlite;
using WorkFlowCore.Common.Authorization.JWT;
using Volo.Abp;
using WorkFlowCore.Plugins;
using System.Threading.Tasks;
using WorkFlowCore.Framework.EventHandlers.Extensions;
using WorkFlowCore.Framework.Utils;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.Extensions.Logging;

namespace WorkFlowCore.Framework
{
    [DependsOn(typeof(AbpEventBusModule))]
    [DependsOn(typeof(WorkFlowCoreModule))]
    [DependsOn(typeof(AbpEntityFrameworkCoreMySQLModule))]
    [DependsOn(typeof(AbpUnitOfWorkModule))]
    public class WorkFlowCoreFrameworkModule : AbpModule
    {
        public override void PreConfigureServices(ServiceConfigurationContext context)
        {
            WorkFlowCoreFrameworkOptions.DbType = FrameworkConfigOrmType.MySql;
        }


        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            
            base.ConfigureServices(context);
            
            var services = context.Services;
            services.GetConfiguration().GetCustomConnectionString();

            services.AddScoped(typeof(IBasicRepository<,>), typeof(BasicRepository4EF<,>));
            services.AddScoped(typeof(IBasicRepository<>), typeof(BasicRepository4EF<>));
            services.AddScoped(typeof(IWorkStepRepository), typeof(WorkStepRepository4EF));
            services.AddScoped(typeof(IWorkTaskRepository), typeof(WorkTaskRepository4EF));

            services.AddAbpDbContext<WorkflowDbContext>(options =>
            {
                options.AddDefaultRepositories(includeAllEntities: true);
            });

            Configure<AbpDbContextOptions>(options =>
            {
                if (WorkFlowCoreFrameworkOptions.DbType == FrameworkConfigOrmType.MySql)
                {
                    /* The main point to change your DBMS.
                     * See also WorkflowMigrationsDbContextFactory for EF Core tooling. */
                    //options.UseMySQL();
                    options.Configure(op =>
                    {
                        op.DbContextOptions.UseMySql(services.GetConfiguration().GetValueFromManyChanels("ConnectionStrings:Default"), new MySqlServerVersion("8.0"));
                    });
                }
                else if (WorkFlowCoreFrameworkOptions.DbType == FrameworkConfigOrmType.LocalMemory)
                {
                    var connection = new SqliteConnection("Data Source=:memory:");
                    connection.Open();

                    var op = new DbContextOptionsBuilder<WorkflowDbContext>()
                        .UseSqlite(connection)
                        .Options;

                    using (var context = new WorkflowDbContext(op))
                    {
                        context.GetService<IRelationalDatabaseCreator>().CreateTables();
                    }

                    options.Configure(context =>
                    {
                        context.DbContextOptions.UseSqlite(connection);
                    });
                }
            });





            //services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            //事件处理
            services.AddScoped<SendTaskEventHandler>();
            services.AddScoped<TaskFinishedEventHandler>();
            services.AddScoped<AutoHandleStepsEventHandler>();

            var assembly = typeof(WorkFlowCoreFrameworkModule).Assembly;


            //注册条件和选择器
            #region 注册条件和选择器
            try
            {
                services.AddScoped<UserSelectorManager>();
                services.AddScoped<ConditionManager>();
                //项目实现的
                UserSelectorManager.RegisterSelector(services, assembly);
                ConditionManager.Registercondition(services, assembly);


                ////外部插件注册的
                //services.LoadPlugins(Path.Combine(AppContext.BaseDirectory, "Plugins", "UserSelectors"), plugins =>
                //{
                //    UserSelectorManager.RegisterSelector(plugins.Select(p => p.Assembly).ToArray());

                //});
                //services.LoadPlugins(Path.Combine(AppContext.BaseDirectory, "Plugins", "Conditions"), plugins =>
                //{
                //    ConditionManager.Registercondition(plugins.Select(p => p.Assembly).ToArray());
                //});
            }
            catch (Exception ex)
            {
                //
            }
            #endregion

            #region 自定义认证插件
            var verifyExtensionType = typeof(DefaultCustomizationVerifyExtension);
            //注册自定义鉴权认证
            PluginManager.Register(new ManifestWithConfig(verifyExtensionType.FullName, "默认自定义鉴权", "接受业务端认证凭据，转发给业务端认证，得到用户信息", "", "default", assembly));

            //注册身份认证
            context.Services.AddScoped(typeof(ICustomizationVerify[]), provider => provider.GetRequiredService<PluginManager>().ResolveAll<ICustomizationVerifyExtension>());
            #endregion

            #region 自定义流程状态变更同步插件
            PluginManager.RegisterPluginType(typeof(ICustomTaskStateChangeEventEventHandler), "自定流程审批状态变化处理器");
            var taskStateChangeEventEventHandlerExtensionType = typeof(CustomTaskStateChangeEventEventHandlerExtension);
            //自定义流程状态变更同步插件
            PluginManager.Register(new ManifestWithConfig(taskStateChangeEventEventHandlerExtensionType.FullName, "默认流程审批状态变化处理", "当流程状态变化时，通过插件配置的{url} post 同步到外部系统", "", "default", assembly));
            #endregion


            services.AddLogging(config =>
            {
                config.AddLog4Net("log4net.config");
            });
        }

        public override void PostConfigureServices(ServiceConfigurationContext context)
        {
            base.PostConfigureServices(context);

            context.Services.Replace(new ServiceDescriptor(typeof(IWorkflowSession), typeof(DefaultSession), ServiceLifetime.Scoped));


            //依赖模块默认注册了 NullCustomizationVerify ，所以这里要通过替换的方式来取代之前的
            //context.Services.Replace(new ServiceDescriptor(typeof(ICustomizationVerify), typeof(DefaultCustomizationVerify), ServiceLifetime.Scoped));


        }

        public override void OnApplicationInitialization(ApplicationInitializationContext context)
        {
            base.OnApplicationInitialization(context);
        }

    }
}
